// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 该文件为平台实现sysSocket，为
// 设置SetNonblock和CloseOnExec提供快速路径。

// go:build dragonfly | | freebsd | | illumos | | linux | | netbsd | | | openbsd 

package net

import (
	"internal/poll"
	"os"
	"syscall"
)

// 围绕套接字系统调用进行包装，该调用将返回的文件
// 描述符标记为非阻塞，并在exec上关闭。
func sysSocket(family, sotype, proto int) (int, error) {
	s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto)
	// 在Linux上，SOCK_NONBLOCK和SOCK_CLOEXEC标志是
	// 在2.6.27内核中引入的，在FreeBSD上，这两个标志都是
	// 在10内核中引入的。如果我们在Linux上遇到EINVAL错误
	// 或在FreeBSD上遇到EPROTONOSUPPORT错误，请退回到没有它们的情况下使用
	// 套接字。
	switch err {
	case nil:
		return s, nil
	default:
		return -1, os.NewSyscallError("socket", err)
	case syscall.EPROTONOSUPPORT, syscall.EINVAL:
	}

	// 见/syscall/exec_unix。请查阅ForkLock的描述。
	syscall.ForkLock.RLock()
	s, err = socketFunc(family, sotype, proto)
	if err == nil {
		syscall.CloseOnExec(s)
	}
	syscall.ForkLock.RUnlock()
	if err != nil {
		return -1, os.NewSyscallError("socket", err)
	}
	if err = syscall.SetNonblock(s, true); err != nil {
		poll.CloseFunc(s)
		return -1, os.NewSyscallError("setnonblock", err)
	}
	return s, nil
}
